/* 
 * File:   UsersDB.cpp
 * Author: nahuel
 * 
 * Created on June 4, 2013, 8:34 PM
 */

#include "common_UsersDB.h"
#include "common_md5.h"

const std::string UsersDB::_rootNodeName = "Users";
const std::string UsersDB::_userNodeName = "user";
const std::string UsersDB::_usernameAttrName = "username";
const std::string UsersDB::_hashedPswAttrName = "hashed_password";

void UsersDB::_CrearArchivo() {
    _dbFile = new TiXmlDocument();
    
    TiXmlDeclaration * decl = new TiXmlDeclaration( "1.0", "", "" );
    
	TiXmlElement* rootNode = new TiXmlElement(_rootNodeName.c_str());
    
    _dbFile->LinkEndChild(decl);
    _dbFile->LinkEndChild(rootNode);
    
    _dbFile->SaveFile(_filePath.c_str());
    
    // TODO: Deletes??
}

UsersDB::UsersDB(const std::string& filePath) {
    _filePath = filePath;
    _dbFile = new TiXmlDocument(filePath.c_str());
    
    if (!_dbFile->LoadFile()) {
        _CrearArchivo();
    }	
}

bool UsersDB::AgregarUsuario(const std::string& usuario, const std::string& password) {
    TiXmlNode* rootNode = _dbFile->FirstChild(_rootNodeName.c_str());
    TiXmlElement* newUserNode = new TiXmlElement(_userNodeName.c_str());
    
    if (ExisteUsuario(usuario)) return false;
    
    char hashPsw[33];
    calcularHashMD5Bloque(password.c_str(), password.size(), hashPsw);   
    
    newUserNode->SetAttribute(UsersDB::_usernameAttrName.c_str(), usuario.c_str());
    newUserNode->SetAttribute(UsersDB::_hashedPswAttrName.c_str(), hashPsw);
    
    rootNode->LinkEndChild(newUserNode);
    
    _dbFile->SaveFile(_filePath.c_str());
    
    return true;
}

bool UsersDB::ExisteUsuario(const std::string& usuario) {
    TiXmlNode* rootNode = _dbFile->FirstChild(_rootNodeName.c_str());
    TiXmlElement* child = rootNode->FirstChildElement();   
    
    while (child) {        
        if (std::string(child->Attribute(UsersDB::_usernameAttrName.c_str())) == usuario) {
            return true;
        }
        
        child = child->NextSiblingElement();
    }
    
    return false;    
}

bool UsersDB::AutenticarUsuario(const std::string& usuario, const std::string& password) {
    TiXmlNode* rootNode = _dbFile->FirstChild(_rootNodeName.c_str());
    TiXmlElement* child = rootNode->FirstChildElement();
    
    char hashPsw[33];
    calcularHashMD5Bloque(password.c_str(), password.size(), hashPsw);
    std::string hashedPsw(hashPsw);
    
    while (child) {        
        if (std::string(child->Attribute(UsersDB::_usernameAttrName.c_str())) == usuario &&
            std::string(child->Attribute(UsersDB::_hashedPswAttrName.c_str())) == hashedPsw) {
            return true;
        }
        
        child = child->NextSiblingElement();
    }
    
    return false;    
}

bool UsersDB::DeleteUsuario(const std::string& usuario) {
    TiXmlNode* rootNode = _dbFile->FirstChild(_rootNodeName.c_str());
    TiXmlElement* child = rootNode->FirstChildElement();   
    
    while (child) {
        if (std::string(child->Attribute(UsersDB::_usernameAttrName.c_str())) == usuario) {
            rootNode->RemoveChild((TiXmlNode*)child);
            _dbFile->SaveFile(_filePath.c_str());
            
            return true;
        }
        
        child = child->NextSiblingElement();
    }
    
    return false;    
}

bool UsersDB::CambiarPassword(const std::string& usuario, const std::string& nuevaPsw) {
    TiXmlNode* rootNode = _dbFile->FirstChild(_rootNodeName.c_str());
    TiXmlElement* child = rootNode->FirstChildElement();   
    
    while (child) {        
        if (std::string(child->Attribute(UsersDB::_usernameAttrName.c_str())) == usuario) {
            char hashPsw[33];
            calcularHashMD5Bloque(nuevaPsw.c_str(), nuevaPsw.size(), hashPsw);
            
            TiXmlElement* newNode = new TiXmlElement(_userNodeName.c_str());
            newNode->SetAttribute(UsersDB::_usernameAttrName.c_str(), usuario.c_str());
            newNode->SetAttribute(UsersDB::_hashedPswAttrName.c_str(), hashPsw);
            
            rootNode->RemoveChild((TiXmlNode*)child);
            rootNode->LinkEndChild(newNode);
    
            _dbFile->SaveFile(_filePath.c_str());          
            
            return true;
        }
        
        child = child->NextSiblingElement();        
    }
    
    return false;
}


UsersDB::~UsersDB() {
    delete _dbFile;
}

